package cn.lili.modules.wallet.serviceimpl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.lili.cache.LockPrefix;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.event.TransactionCommitSendMQEvent;
import cn.lili.common.exception.ServiceException;
import cn.lili.common.security.AuthUser;
import cn.lili.common.security.context.UserContext;
import cn.lili.common.security.enums.SceneEnums;
import cn.lili.common.utils.*;
import cn.lili.common.vo.ResultMessage;
import cn.lili.exchange.AmqpExchangeProperties;
import cn.lili.modules.distribution.client.DistributionClient;
import cn.lili.modules.distribution.entity.dos.Distribution;
import cn.lili.modules.member.client.UserClient;
import cn.lili.modules.member.entity.dos.User;
import cn.lili.modules.payment.entity.dos.OutOrderDetailLog;
import cn.lili.modules.payment.entity.dos.UserWallet;
import cn.lili.modules.payment.entity.dos.WalletLog;
import cn.lili.modules.payment.entity.dto.*;
import cn.lili.modules.payment.entity.enums.PlatformWalletEnum;
import cn.lili.modules.payment.entity.enums.UserFmoneyServiceEnum;
import cn.lili.modules.payment.entity.enums.UserPointServiceEnum;
import cn.lili.modules.payment.entity.enums.WalletServiceTypeEnum;
import cn.lili.modules.payment.entity.vo.WalletVO;
import cn.lili.modules.payment.service.OutOrderDetailLogService;
import cn.lili.modules.store.client.StoreClient;
import cn.lili.modules.store.entity.vos.StoreVO;
import cn.lili.modules.urbansubstation.client.UrbanSubstationClient;
import cn.lili.modules.urbansubstation.entity.dos.UrbanSubstation;
import cn.lili.modules.wallet.aop.annotation.FMoneyLogPoint;
import cn.lili.modules.wallet.aop.annotation.PointLogPoint;
import cn.lili.modules.wallet.manage.WalletMange;
import cn.lili.modules.wallet.mapper.WalletMapper;
import cn.lili.modules.wallet.service.WalletLogService;
import cn.lili.modules.wallet.service.WalletService;
import cn.lili.routing.UserRoutingKey;
import cn.lili.util.TemplateHtml;
import cn.lili.util.TemplateMessage;
import cn.wildfirechat.pojos.SendMessageResult;
import cn.wildfirechat.sdk.ChannelServiceApi;
import cn.wildfirechat.sdk.model.IMResult;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.api.PayApi;
import com.api.UserApi;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pojos.OpenAppUser;
import com.pojos.UserRes;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;


/**
 * 会员余额业务层实现
 *
 * @author pikachu
 * @since 2020-02-25 14:10:16
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class WalletServiceImpl extends ServiceImpl<WalletMapper, UserWallet> implements WalletService {


    /**
     * 预存款日志
     */
    private final WalletLogService walletLogService;

    private final RedissonClient redisson;

    private final ApplicationEventPublisher applicationEventPublisher;

    private final AmqpExchangeProperties amqpExchangeProperties;
    /**
     * 会员
     */
    private final UserClient userClient;

    private final StoreClient storeClient;

    private final UrbanSubstationClient urbanSubstationClient;

    private final DistributionClient distributionClient;
    private final WalletMange walletMange;

    private final PayApi payApi;

    private final OutOrderDetailLogService outOrderDetailLogService;

    private final UserApi userApi;

    private final ChannelServiceApi channelServiceApi;


    @Override
    public WalletVO getWalletVO(String userId) {
        UserWallet userWallet = this.getFromUserid(userId);
        WalletVO walletVO = new WalletVO(userWallet);
        Distribution distribution = distributionClient.getDistribution(userId);
        if (distribution != null) {
            walletVO.setRebateTotal(distribution.getRebateTotal());
        }
        return walletVO;
    }

    @Override
    public UserWallet getFromUserid(String userId) {
        //获取用户钱包信息
        UserWallet userWallet = this.getOne(new LambdaQueryWrapper<UserWallet>().eq(UserWallet::getUserId, userId), false);

        //如果用户钱包信息不存在则同步重新建立预存款信息
        if (userWallet == null) {

            //兼容极端情况，系统钱包被删除问题处理
            if (Long.parseLong(userId) < 0) {
                userWallet = new UserWallet();
                userWallet.setId(userId);
                userWallet.setUserId(userId);
                userWallet.setNickName("系统");
                userWallet.setPoints(0D);
                userWallet.setTotalPoints(0D);
                userWallet.setBalance(0D);
                userWallet.setFrozenBalance(0D);
                userWallet.setScene(SceneEnums.SYSTEM.name());
                userWallet.setFmoney(0D);
                userWallet.setTotalFmoney(0D);
                this.save(userWallet);
                return userWallet;
            }

            //先判定普通用户是否存在
            User user = userClient.getById(userId);
            if (user != null) {
                userWallet = new UserWallet(user);
                this.save(userWallet);
                return userWallet;
            }
            //再判定店铺是否存在
            try {
                StoreVO store = storeClient.getStore(userId);
                if (store != null) {
                    userWallet = new UserWallet(store);
                    this.save(userWallet);
                    return userWallet;
                }
            }catch (Exception e){
                log.error(e.getMessage());
            }

            UrbanSubstation urbanSubstation = urbanSubstationClient.getUrbanSubstation(UserContext.getCurrentUser().getId());
            if (urbanSubstation != null) {
                userWallet = new UserWallet(urbanSubstation);
                this.save(userWallet);
                return userWallet;
            }
            throw new ServiceException(ResultCode.USER_NOT_EXIST);

        }
        return userWallet;
    }

    @Override
    @Transactional
    public void increaseWithdrawal(UserWalletUpdateDTO userWalletUpdateDTO) {

        try {
            //检测用户钱包讯息是否存在，如果不存在则新建
            UserWallet userWallet = this.getFromUserid(userWalletUpdateDTO.getUserId());
            userWalletUpdateDTO.setNickname(userWallet.getNickName());
            //新增预存款日志
            WalletLog walletLog = new WalletLog(userWalletUpdateDTO);
            nicknameHandler(walletLog);
            walletLogService.save(walletLog);

            //余额变动
            baseMapper.increaseWithdrawal(userWalletUpdateDTO.getUserId(), userWalletUpdateDTO.getAmount());
        } catch (Exception e) {
            log.error("冻结金额转移至余额失败", e);
            throw e;
        }
    }


    @Override
    @Transactional
    public void reduceWithdrawal(UserWalletUpdateDTO userWalletUpdateDTO) {

        RLock lock = null;
        //锁顶钱包
        try {
            lock = redisson.getLock(LockPrefix.WALLET.getPrefix() + userWalletUpdateDTO.getUserId());
            lock.lock();
            //检测用户钱包讯息是否存在，如果不存在则新建
            UserWallet userWallet = this.getFromUserid(userWalletUpdateDTO.getUserId());
            //减少预存款，需要校验 如果不够扣减预存款
            if (0 > CurrencyUtil.sub(userWallet.getBalance(), userWalletUpdateDTO.getAmount())) {
                throw new ServiceException(ResultCode.WALLET_WITHDRAWAL_INSUFFICIENT);
            }
            baseMapper.reduceWithdrawal(userWalletUpdateDTO.getUserId(), userWalletUpdateDTO.getAmount());
            //新增预存款日志
            WalletLog walletLog = new WalletLog(userWallet.getNickName(), userWalletUpdateDTO, true);
            nicknameHandler(walletLog);
            walletLogService.save(walletLog);
        } catch (ServiceException e) {
            throw e;
        } finally {
            if (lock != null) lock.unlock();
        }

    }

    @Override
    @Transactional
    public void recharge(UserWalletUpdateDTO userWalletUpdateDTO) {

        //线下转账进来，则用户增加余额，平台余额充值钱包增加

        //检测用户钱包讯息是否存在，如果不存在则新建
        this.getFromUserid(userWalletUpdateDTO.getUserId());
        this.getFromUserid(userWalletUpdateDTO.getPlatformWalletId());


        //新增预存款日志
        WalletLog walletLog = new WalletLog(userWalletUpdateDTO);
        nicknameHandler(walletLog);
        nicknameHandler(walletLog);
        walletLogService.save(walletLog);


        //新增平台钱包预存款日志
        walletLog.setId(null);
        walletLog.setUserId(userWalletUpdateDTO.getPlatformWalletId());
        nicknameHandler(walletLog);
        walletLogService.save(walletLog);


        //余额充值
        baseMapper.recharge(userWalletUpdateDTO.getUserId(), userWalletUpdateDTO.getAmount());

        //线下钱包金额变更
        baseMapper.recharge(userWalletUpdateDTO.getPlatformWalletId(), userWalletUpdateDTO.getAmount());
    }

    @Override
    @Transactional
    public void increase(UserWalletUpdateDTO userWalletUpdateDTO) {


        try {
            //检测用户钱包讯息是否存在，如果不存在则新建
            this.getFromUserid(userWalletUpdateDTO.getUserId());
            this.getFromUserid(PlatformWalletEnum.BALANCE.getWalletUserId());
            //余额转移 用户余额增加，平台余额减少
            baseMapper.reduce(PlatformWalletEnum.BALANCE.getWalletUserId(), userWalletUpdateDTO.getAmount());
            baseMapper.recharge(userWalletUpdateDTO.getUserId(), userWalletUpdateDTO.getAmount());


            //用户日志持久化
            WalletLog walletLog = new WalletLog(userWalletUpdateDTO);
            nicknameHandler(walletLog);
            walletLogService.save(walletLog);

            //平台日志持久化
            walletLog.setId(null);
            walletLog.setUserId(PlatformWalletEnum.BALANCE.getWalletUserId());
            walletLog.setMoney(-walletLog.getMoney());
            nicknameHandler(walletLog);
            walletLogService.save(walletLog);

            if (userWalletUpdateDTO.getServiceType().equals(WalletServiceTypeEnum.REFUND)) {
                User user = userClient.getById(userWalletUpdateDTO.getUserId());
                if (null != user && StringUtils.isNotEmpty(user.getOpenId())) {
                    OpenAppUser openAppUser = userApi.getUserinfoByOpenId(user.getOpenId());
                    if (null != openAppUser) {
                        List<String> targets = new ArrayList<>();
                        targets.add(openAppUser.getUId());
                        TemplateMessage message = TemplateHtml.sendMessageForHtml("商城余额退回", userWalletUpdateDTO.getAmount().toString(), userWalletUpdateDTO.getOrderSn(), "退款", "WALLET", 1);
                        try {
                            IMResult<SendMessageResult> sendMessageResultIMResult = channelServiceApi.sendMessage(0, targets, message);
                            log.info("发送消息结果：{}", JSONObject.toJSONString(sendMessageResultIMResult));
                        } catch (Exception ex) {
                            log.error("发送消息失败", ex);
                            throw new RuntimeException(ex);
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("余额转移异常", e);
            throw e;
        }
    }


    @Override
    @Transactional
    public void reduce(UserWalletUpdateDTO userWalletUpdateDTO) {

        RLock lock = null;
        //锁顶钱包

        try {
            lock = redisson.getLock(LockPrefix.WALLET.getPrefix() + userWalletUpdateDTO.getUserId());
            lock.lock();
            //检测用户钱包讯息是否存在，如果不存在则新建
            UserWallet userWallet = this.getFromUserid(userWalletUpdateDTO.getUserId());
            //减少预存款，需要校验 如果不够扣减预存款
            if (0 > CurrencyUtil.sub(userWallet.getBalance(), userWalletUpdateDTO.getAmount())) {
                //小于0则表示平台钱包，否则是用户，且钱包扣减后小于0，则抛出异常
                if (Long.parseLong(userWalletUpdateDTO.getUserId()) > 0) {
                    throw new ServiceException(ResultCode.BALANCE_NOT_ENOUGH);
                }
            }
            //余额扣除
            baseMapper.reduce(userWalletUpdateDTO.getUserId(), userWalletUpdateDTO.getAmount());
            //余额转移 用户余额增加，平台余额减少
            baseMapper.recharge(userWalletUpdateDTO.getPlatformWalletId(), userWalletUpdateDTO.getAmount());
            //新增预存款日志
            WalletLog walletLog = new WalletLog(userWallet.getNickName(), userWalletUpdateDTO, true);
            nicknameHandler(walletLog);
            walletLogService.save(walletLog);
            //平台日志持久化
            walletLog.setId(null);
            walletLog.setUserId(userWalletUpdateDTO.getPlatformWalletId());
            walletLog.setMoney(-walletLog.getMoney());
            nicknameHandler(walletLog);
            walletLogService.save(walletLog);

            User user = userClient.getById(userWalletUpdateDTO.getUserId());
            if (null != user && StringUtils.isNotEmpty(user.getOpenId())) {
                OpenAppUser openAppUser = userApi.getUserinfoByOpenId(user.getOpenId());
                if (null != openAppUser) {
                    List<String> targets = new ArrayList<>();
                    targets.add(openAppUser.getUId());
                    TemplateMessage message = TemplateHtml.sendMessageForHtml("商城余额支付", userWalletUpdateDTO.getAmount().toString(), userWalletUpdateDTO.getOrderSn(), "购买商品", "WALLET", 0);
                    try {
                        IMResult<SendMessageResult> sendMessageResultIMResult = channelServiceApi.sendMessage(0, targets, message);
                        log.info("发送消息结果：{}", JSONObject.toJSONString(sendMessageResultIMResult));
                    } catch (Exception ex) {
                        log.error("发送消息失败", ex);
                        throw new RuntimeException(ex);
                    }
                }
            }
        } catch (Exception e) {
            throw e;
        } finally {
            if (lock != null) lock.unlock();
        }
    }

    @Override
    @Transactional
    public void withdrawal(UserWalletUpdateDTO userWalletUpdateDTO) {
        RLock lock = null;
        //锁顶钱包

        try {
            lock = redisson.getLock(LockPrefix.WALLET.getPrefix() + userWalletUpdateDTO.getUserId());
            lock.lock();
            //检测用户钱包讯息是否存在，如果不存在则新建
            UserWallet userWallet = this.getFromUserid(userWalletUpdateDTO.getUserId());
            //减少预存款，需要校验 如果不够扣减预存款
            if (0 > CurrencyUtil.sub(userWallet.getBalance(), userWalletUpdateDTO.getAmount())) {
                //小于0则表示平台钱包，否则是用户，且钱包扣减后小于0，则抛出异常
                if (Long.parseLong(userWalletUpdateDTO.getUserId()) > 0) {
                    throw new ServiceException(ResultCode.BALANCE_NOT_ENOUGH);
                }
            }
            //余额扣除
            baseMapper.reduce(userWalletUpdateDTO.getUserId(), userWalletUpdateDTO.getAmount());
            //新增预存款日志
            WalletLog walletLog = new WalletLog(userWallet.getNickName(), userWalletUpdateDTO, true);
            nicknameHandler(walletLog);
            walletLogService.save(walletLog);
        } catch (Exception e) {
            throw e;
        } finally {
            if (lock != null) lock.unlock();
        }
    }

    @Override
    @Transactional
    public void reduceFrozen(UserWalletUpdateDTO userWalletUpdateDTO) {

        RLock lock = null;
        //锁顶钱包

        try {
            lock = redisson.getLock(LockPrefix.WALLET.getPrefix() + userWalletUpdateDTO.getUserId());
            lock.lock();
            //检测用户钱包讯息是否存在，如果不存在则新建
            UserWallet userWallet = this.getFromUserid(userWalletUpdateDTO.getUserId());
            //校验此金额是否超过冻结金额
            if (0 > CurrencyUtil.sub(userWallet.getFrozenBalance(), userWalletUpdateDTO.getAmount())) {
                throw new ServiceException(ResultCode.WALLET_WITHDRAWAL_FROZEN_AMOUNT_INSUFFICIENT);
            }
            baseMapper.reduceFrozenBalance(userWalletUpdateDTO.getUserId(), userWalletUpdateDTO.getAmount());
            //新增预存款日志
            WalletLog walletLog = new WalletLog(userWallet.getNickName(), userWalletUpdateDTO, true);
            nicknameHandler(walletLog);
            walletLogService.save(walletLog);

            //平台余额扣除计账
            baseMapper.reduce(userWalletUpdateDTO.getPlatformWalletId(), userWalletUpdateDTO.getAmount());

            walletLog.setId(null);
            walletLog.setUserId(userWalletUpdateDTO.getPlatformWalletId());
            nicknameHandler(walletLog);
            walletLogService.save(walletLog);

        } catch (Exception e) {
            throw e;
        } finally {
            if (lock != null) lock.unlock();
        }
    }

    @Override
    public void setUserWalletPassword(String password) {
        //对密码进行加密
        String pwd = new BCryptPasswordEncoder().encode(password);
        UserWallet wallet = this.getFromUserid(UserContext.getCurrentUser().getExtendId());
        LambdaUpdateWrapper<UserWallet> updateWrapper = new UpdateWrapper<UserWallet>().lambda();
        updateWrapper.set(UserWallet::getWalletPassword, pwd);
        updateWrapper.eq(UserWallet::getId, wallet.getId());
        this.update(updateWrapper);
    }

    @Override
    public void updateUserWalletPassword(String oldPassword, String password) {

        UserWallet wallet = this.getFromUserid(UserContext.getCurrentUser().getExtendId());
        if (!new BCryptPasswordEncoder().matches(oldPassword, wallet.getWalletPassword())) {
            throw new ServiceException(ResultCode.USER_OLD_PASSWORD_ERROR);
        }

        this.setUserWalletPassword(password);
    }

    @Override
    public Boolean checkPassword() {
        //获取当前登录会员
        AuthUser authUser = UserContext.getCurrentUser();
        //构建查询条件
        QueryWrapper<UserWallet> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_id", authUser.getExtendId());
        UserWallet wallet = this.getOne(queryWrapper);
        return wallet != null && !CharSequenceUtil.isEmpty(wallet.getWalletPassword());
    }


    @Override
    @PointLogPoint
    @Transactional
    public void updateMemberPoint(UserPointUpdateDTO userPointUpdateDTO) {

        System.out.println(this);
        System.out.println("=========更新绿色积分===========");
        RLock lock = null;
        //锁顶钱包

        try {
            //获取当前会员信息
            UserWallet userWallet = this.getFromUserid(userPointUpdateDTO.getUserId());
            if (userWallet != null) {
                //如果增加积分
                if (Boolean.TRUE.equals(userPointUpdateDTO.getUserPointServiceEnum().getAdd())) {
                    baseMapper.addPoints(userPointUpdateDTO.getPoints(), userPointUpdateDTO.getUserId());
                }
                //否则扣除积分
                else {
                    baseMapper.reducePoints(userPointUpdateDTO.getPoints(), userPointUpdateDTO.getUserId());
                }
                applicationEventPublisher.publishEvent(
                        TransactionCommitSendMQEvent.builder()
                                .source("USER_POINT_CHANGE")
                                .exchange(amqpExchangeProperties.getUser())
                                .routingKey(UserRoutingKey.USER_POINT_CHANGE)
                                .message(userPointUpdateDTO)
                                .build()
                );
            }
        } catch (Exception e) {
            throw e;
        } finally {
            if (lock != null) lock.unlock();
        }
    }

    @Override
    @Transactional
    public void updateMemberPointV2(UserPointUpdateDTO userPointUpdateDTO) {

        System.out.println(JSON.toJSONString(userPointUpdateDTO));
        System.out.println("=========更新绿色积分===========");
        RLock lock = null;
        //锁顶钱包

        try {
            lock = redisson.getLock(LockPrefix.POINTS.getPrefix() + userPointUpdateDTO.getUserId());
            lock.lock();
            // 处理用户打款绿色积分
            walletMange.memberGreen(userPointUpdateDTO);
            //处理商家打款绿色积分
            walletMange.storeGreen(userPointUpdateDTO);
            //处理代理商打款绿色积分
            walletMange.supplierGreen(userPointUpdateDTO);
            //处理直推打款绿色积分
            walletMange.lowerGreen(userPointUpdateDTO);
            //处理间推打款绿色积分
            walletMange.lowerSubGreen(userPointUpdateDTO);
            //处理工会打款绿色积分
            walletMange.memberUnion(userPointUpdateDTO);
        } catch (Exception e) {
            throw e;
        } finally {
            if (lock != null) lock.unlock();
        }
    }


    @Override
    @FMoneyLogPoint
    @Transactional
    public void updateMemberFmoney(UserFmoneyUpdateDTO userPointUpdateDTO) {


        RLock lock = null;
        //锁顶钱包

        try {
            lock = redisson.getLock(LockPrefix.FMONEY.getPrefix() + userPointUpdateDTO.getUserId());
            lock.lock();
            //获取当前会员信息
            UserWallet userWallet = this.getFromUserid(userPointUpdateDTO.getUserId());
            if (userWallet != null) {
                //如果增加积分
                if (Boolean.TRUE.equals(userPointUpdateDTO.getUserFmoneyServiceEnum().getAdd())) {
                    baseMapper.addFmoney(userPointUpdateDTO.getFmoney(), userPointUpdateDTO.getUserId());
                }
                //否则扣除积分
                else {
                    baseMapper.reduceFmoney(userPointUpdateDTO.getFmoney(), userPointUpdateDTO.getUserId());
                }
                applicationEventPublisher.publishEvent(
                        TransactionCommitSendMQEvent.builder()
                                .source("USER_FMONEY_CHANGE")
                                .exchange(amqpExchangeProperties.getUser())
                                .routingKey(UserRoutingKey.USER_FMONEY_CHANGE)
                                .message(userPointUpdateDTO)
                                .build()
                );
            }
        } catch (Exception e) {
            throw e;
        } finally {
            if (lock != null) lock.unlock();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void profitSharing(ProfitSharingRequestDTO profitSharingRequestDTO) {

        log.info("=========profitSharingRequestDTO=======" ,profitSharingRequestDTO);

        // 余额各个环节拿到自己的余额
        for (OutOrderItem outOrderItem : profitSharingRequestDTO.getOutOrderItems()) {
            if (outOrderItem.getPrice() > 0) {
                try {
                    SpringContextUtil.getBean(WalletService.class).increase(
                            UserWalletUpdateDTO.builder()
                                    .userId(outOrderItem.getUserId())
                                    .amount(outOrderItem.getPrice())
                                    .orderSn(outOrderItem.getOrderSn())
                                    .detail(outOrderItem.generateDescription())
                                    .outTradeNo(SnowFlake.createStr("OTN"))
                                    .transactionId(SnowFlake.createStr("TI"))
                                    .serviceType(WalletServiceTypeEnum.SETTLEMENT)
                                    .platformWalletId(PlatformWalletEnum.BALANCE.getWalletUserId())
                                    .build());
                }catch (Exception e){
                    log.error(e.getMessage());
                }
            }
        }

        // 绿色积分分佣
        for (OutPointOrderItem outOrderItem : profitSharingRequestDTO.getOutPointOrderItem()) {
            if (outOrderItem.getPrice() > 0) {
                SpringContextUtil.getBean(WalletService.class).updateMemberPointV2(
                        UserPointUpdateDTO.builder()
                                .userId(outOrderItem.getUserId())
                                .points(outOrderItem.getPrice())
                                .userPointServiceEnum(UserPointServiceEnum.PAYMENT_GIFT)
                                .orderSn(outOrderItem.getOrderSn())
                                .scene(outOrderItem.getScene())
                                .description(outOrderItem.getNickname()).build());

            }
        }

        // F分分配给对应账户体系
        for (OutFmoneyOrderItem outOrderItem : profitSharingRequestDTO.getOutFmoneyOrderItem()) {
            if (outOrderItem.getPrice() > 0) {
                SpringContextUtil.getBean(WalletService.class).updateMemberFmoney(
                        UserFmoneyUpdateDTO.builder()
                                .userId(outOrderItem.getUserId())
                                .fmoney(outOrderItem.getPrice())
                                .userFmoneyServiceEnum(UserFmoneyServiceEnum.SHOPPING)
                                .description("F分购物").build());

            }
        }


    }

    /**
     * 处理昵称
     *
     * @param walletLog 钱包日志
     */
    private void nicknameHandler(WalletLog walletLog) {
        if (Long.parseLong(walletLog.getUserId()) <= 0) {
            walletLog.setNickName("系统");
        } else {
            //如果昵称为空 特殊处理
            if (CharSequenceUtil.isEmpty(walletLog.getNickName())) {
                try {
                    User user = userClient.getById(walletLog.getUserId());
                    walletLog.setNickName(user.getNickName());
                } catch (Exception e) {
                    log.error("获取用户信息失败", e.getMessage());
                }
            }
        }
    }

    /**
     * 账户冲账
     * @param userId
     */
    @Override
    public void strikeBalance (String userId) {
        if (null == UserContext.getCurrentUser() || !SceneEnums.MANAGER.name().equals(UserContext.getCurrentUser().getScene().name())) {
            throw new ServiceException("权限不足");
        }
        User user = userClient.getById(userId);
        if (null == user) {
            throw new ServiceException("用户不存在");
        }
        if (CharSequenceUtil.isEmpty(user.getOpenId())) {
            throw new ServiceException("用户OpenId不存在");
        }
        UserRes userRes = payApi.getUserMoney(user.getOpenId());
        int tradeType = 0;//固定值
        int operationType = 103;//用户自定义
        BigInteger money = new BigInteger(userRes.getGmoney());
        payApi.strikeBalance(user.getOpenId(), "绿色积分账户异常,冲账金额：" + money, money.intValue(), tradeType, operationType, "GMONEY");
    }

    /**
     * 分账余额对冲
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void shareProfitStrike (String userId) {
        if (null == UserContext.getCurrentUser() || !SceneEnums.MANAGER.name().equals(UserContext.getCurrentUser().getScene().name())) {
            throw new ServiceException("权限不足");
        }

        if (StringUtils.isEmpty(userId)) {
            throw new ServiceException("参数异常");
        }

        try {
            List<OutOrderDetailLog> outOrderDetailLogList = outOrderDetailLogService.shareProfitStrike(userId);
            if (!outOrderDetailLogList.isEmpty()) {
                outOrderDetailLogList.forEach(outOrderDetailLog -> {
                    // 获取用户现有余额
                    UserWallet userWallet = this.getFromUserid(outOrderDetailLog.getSubMchid());
                    // 当前用户余额 - 重复分账金额 + 应该分账金额
                    Double money = CurrencyUtil.sub(userWallet.getBalance(), outOrderDetailLog.getSumAmount());
                    Double balance = CurrencyUtil.add(money, outOrderDetailLog.getAmount());
                    userWallet.setBalance(balance);
                    this.updateById(userWallet);

                    // 删除重复数据
                    LambdaQueryWrapper<OutOrderDetailLog> queryWrapper = new LambdaQueryWrapper<>();
                    queryWrapper.eq(OutOrderDetailLog::getOrderSn, outOrderDetailLog.getOrderSn());
                    queryWrapper.eq(OutOrderDetailLog::getSubMchid, outOrderDetailLog.getSubMchid());
                    queryWrapper.orderByAsc(OutOrderDetailLog::getCreateTime);
                    List<OutOrderDetailLog> outOrderDetailLogs = outOrderDetailLogService.list(queryWrapper);
                    if (!outOrderDetailLogs.isEmpty()) {
                        List<String> ids = outOrderDetailLogs.stream().map(OutOrderDetailLog::getId).toList();
                        OutOrderDetailLog saveOutOrderDetailLog = new OutOrderDetailLog();
                        BeanUtil.copyProperties(outOrderDetailLogs.get(0), saveOutOrderDetailLog, "id");
                        outOrderDetailLogService.deleteShareProfit(ids);
                        outOrderDetailLogService.save(saveOutOrderDetailLog);
                    }

                    LambdaQueryWrapper<WalletLog> queryWrapper2 = new LambdaQueryWrapper<>();
                    queryWrapper2.eq(WalletLog::getUserId, outOrderDetailLog.getSubMchid());
                    queryWrapper2.eq(WalletLog::getOrderSn, outOrderDetailLog.getOrderSn());
                    queryWrapper2.orderByAsc(WalletLog::getCreateTime);
                    List<WalletLog> walletLogList = walletLogService.list(queryWrapper2);
                    if (!walletLogList.isEmpty()) {
                        List<String> ids = walletLogList.stream().map(WalletLog::getId).toList();
                        WalletLog walletLog = new WalletLog();
                        BeanUtil.copyProperties(walletLogList.get(0), walletLog, "id");
                        walletLogService.removeBatchByIds(ids);
                        walletLogService.save(walletLog);
                    }
                });
            }
        }catch (Exception e) {
            throw new ServiceException();
        }
    }

    /**
     * 账户冲账-余额
     * @param userId
     */
    @Override
    public void strikeBalanceByRemainder (String userId) {
        if (null == UserContext.getCurrentUser() || !SceneEnums.MANAGER.name().equals(UserContext.getCurrentUser().getScene().name())) {
            throw new ServiceException("权限不足");
        }
        User user = userClient.getById(userId);
        if (null == user) {
            throw new ServiceException("用户不存在");
        }
        if (CharSequenceUtil.isEmpty(user.getOpenId())) {
            throw new ServiceException("用户OpenId不存在");
        }

        UserRes userRes = payApi.getUserMoney(user.getOpenId());
        int tradeType = 0;//固定值
        int operationType = 103;//用户自定义
        BigInteger money = new BigInteger(userRes.getRemainder());
        payApi.strikeBalance(user.getOpenId(), "余额账户异常,冲账金额：" + money, money.intValue(), tradeType, operationType, "MONEY");
    }


    public ResultMessage<Object> addBalance(String openId, String orderSn, Double money, String remark, String payType) {
        if (StringUtils.isEmpty(openId) || null == money) {
            return ResultUtil.error(500, "参数错误");
        }

        RLock lock = redisson.getLock("add_balance_" + openId);
        try {
            lock.lock();
            User user = userClient.getByOpenId(openId, SceneEnums.MEMBER.name());
            if (null == user) {
                return ResultUtil.error(500, "用户不存在");
            }

            UserWallet userWallet = this.getFromUserid(user.getId());
            if (null == userWallet) {
                return ResultUtil.error(500, "用户钱包不存在");
            }
            if (null == userWallet.getBalance()) {
                userWallet.setBalance(0D);
            }
            userWallet.setBalance(CurrencyUtil.add(userWallet.getBalance(), money));
            this.updateById(userWallet);

            WalletLog walletLog = new WalletLog();
            walletLog.setUserId(user.getId());
            walletLog.setNickName(user.getNickName());
            walletLog.setMoney(money);
            walletLog.setOrderSn(orderSn);
            walletLog.setServiceType(WalletServiceTypeEnum.GIVE.name());
            walletLog.setDetail(remark);
            walletLogService.save(walletLog);

            if (StringUtils.isNotEmpty(user.getOpenId())) {
                OpenAppUser openAppUser = userApi.getUserinfoByOpenId(user.getOpenId());
                if (null != openAppUser) {
                    List<String> targets = new ArrayList<>();
                    targets.add(openAppUser.getUId());
                    TemplateMessage message = TemplateHtml.sendMessageForHtml("飞语会议返商城余额", money.toString(), orderSn, "飞语会议返现", payType, 1);
                    try {
                        IMResult<SendMessageResult> sendMessageResultIMResult = channelServiceApi.sendMessage(0, targets, message);
                        log.info("发送消息结果：{}", JSONObject.toJSONString(sendMessageResultIMResult));
                    } catch (Exception ex) {
                        log.error("发送消息失败", ex);
                        throw new RuntimeException(ex);
                    }
                }
            }
            return ResultUtil.success();
        }catch (Exception e) {
            log.error("发送余额奖励失败", e);
        }finally {
            if (lock.isLocked()) {
                lock.unlock();
            }

        }
        return ResultUtil.error(500, "余额操作失败");
    }
}